package com.hujing.springsource.a02;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class A02ApplicationContext {

    public static void main(String[] args) {
        // 测试ClassPathXmlApplicationContext容器
//        testClassPathXmlApplicationContext();
        // 测试AnnotationConfigApplicationContext容器
//        testAnnotationConfigApplicationContext();
        testAnnotationConfigServletWebServerApplicationContext();
    }
    
    public static void testAnnotationConfigServletWebServerApplicationContext(){
        AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
    }
    
    private static void testAnnotationConfigApplicationContext(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println("Bean Name: "+name);
        }
    }
    
    /** ClassPathXmlApplicationContext怎么读取xml配置文件的
     *  1. 创建DefaultListableBeanFactory对象，作为Spring IoC容器
     *  2. 创建XmlBeanDefinitionReader对象，读取xml配置文件，并将Bean定义加载到BeanFactory中
     *  3. 调用BeanFactory的getBean方法，获取Bean对象
     * @return
     */
    public DefaultListableBeanFactory doFromClassPathXmlApplicationContext() {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
        return beanFactory;
    }

    private static void testClassPathXmlApplicationContext() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("b01.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println("Bean Name: "+name);
        }

        // 打印bean2的属性bean1
        System.out.println(context.getBean(Bean2.class).getBean1());
    }
    
    @Configuration
    static class WebConfig{
        @Bean
        public ServletWebServerFactory servletWebServerFactory(){
            return new TomcatServletWebServerFactory();
        }
        @Bean
        public DispatcherServlet dispatcherServlet(){
            return new DispatcherServlet();
        }
        @Bean
        public DispatcherServletRegistrationBean registrationBean(DispatcherServlet servlet){
            return new DispatcherServletRegistrationBean(servlet,"/");
        }
        @Bean("/hello")
        public Controller controller1(){
            return (request, response) -> {
                response.getWriter().println("hello");
                return null;
            };
        }
    }
    
    @Configuration
    static class Config{
        @Bean
        public Bean1 bean1(){
            return new Bean1();
        }
        
        @Bean
        public Bean2 bean2(Bean1 bean1){
            Bean2 bean2 = new Bean2();
            bean2.setBean1(bean1);
            return bean2;
        }
    }

    static class Bean1{
        
    }
    
    static class Bean2{
        private Bean1 bean1;
        
        public void setBean1(Bean1 bean1){
            this.bean1 = bean1;
        }
        
        public Bean1 getBean1(){
            return this.bean1;
        }
    }
}

